import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
import { TransformControls } from 'three/examples/jsm/controls/TransformControls.js';
import * as THREE from 'three';

const TRANSFORM_MODE_MENU_ID = 'transform-mode-menu';

interface ControlsOption {
  camera: THREE.PerspectiveCamera;
  scene: THREE.Scene;
  renderer?: THREE.WebGLRenderer;
  boxId: string;
}

/**
 * TODO:
 *  - 守卫增强
 *  - 对于所有enable事件进行记录，再开启不同的enable时，调用上一个enable对应的disable事件
 * @description 处理Three.js中的控件，包括轨道控制和变换控制
 */
export default class Controls {
  /**
   * 轨道控制器实例
   */
  orbitControls: OrbitControls = null;

  /**
   * 变换控制器实例
   */
  transformControls: TransformControls = null;

  /**
   * 控件配置选项
   */
  option: ControlsOption;

  transformModeMenuAbortController: AbortController = null;

  transformModeMenuVisibleMode: Editor.VisibleTransformModes = [];

  fastRotateAbortController: AbortController = null;

  clickPickerAbortController: AbortController = null;

  /** 当前旋转步骤*/
  currentRotationStep = 0;

  constructor(option: ControlsOption) {
    this.option = option;
    this._initOribitControls();
    this._initTransformControls();
  }

  private _initOribitControls(): void {
    const { camera, renderer, scene } = this.option;
    this.orbitControls = new OrbitControls(camera, renderer.domElement);
    renderer.render(scene, camera);
  }

  /**
   * @description 依赖orbitControls
   */
  private _initTransformControls(): void {
    // TODO: 后续修改
    const { camera, renderer, scene } = this.option;
    const transformControls = new TransformControls(camera, renderer.domElement);

    transformControls.addEventListener('mouseDown', () => {
      this.orbitControls.enabled = false;
    });
    transformControls.addEventListener('objectChange', () => {
      renderer.render(scene, camera);
    });
    transformControls.addEventListener('mouseUp', () => {
      this.orbitControls.enabled = true;
      renderer.render(scene, camera);
    });

    scene.add(transformControls as unknown as THREE.Object3D);
    this.transformControls = transformControls;
  }

  /**
   * @description 打开轨道控制 + 模式菜单 + 可选快速旋转
   * - 请进行成对调用: enableTransformModeMenu + detachTransfromControls
   * - 调用detachTransformControls关闭
   * */
  enableTransformModeMenu(menuOption: Editor.TransformModeMenuOption): void {
    this._resetTransfromControls();
    /**
     * 1. menu不存在时
     *    - 创建新的menu
     * 2. 两次的visibleMode不一致时
     *    - 移除原来的menu
     *    - 创建新的menu
     */
    const {
      enableFastRotate = false,
      visibleModes = [
        { mode: 'translate', callback: null },
        { mode: 'rotate', callback: null },
        { mode: 'scale', callback: null },
      ],
    } = menuOption;
    if (
      this.transformModeMenuVisibleMode.length === visibleModes.length &&
      this.transformModeMenuVisibleMode.every((item, index) => item.mode === visibleModes[index].mode)
    )
      return;
    // 防止重复创建
    this._removeTransformModeMenu();

    this.transformModeMenuAbortController = new AbortController();

    const menu = document.createElement('div');
    menu.setAttribute('id', TRANSFORM_MODE_MENU_ID);

    const modes = [
      { mode: 'translate', name: '平移' },
      { mode: 'rotate', name: '旋转' },
      { mode: 'scale', name: '缩放' },
    ];

    // 一次遍历过滤并合并数据
    const filteredModes = modes.reduce((acc, mode) => {
      const visibleItem = visibleModes.find((v) => v.mode === mode.mode);
      if (visibleItem) {
        acc.push({
          ...mode,
          callback: visibleItem.callback,
        });
      }
      return acc;
    }, []);
    filteredModes.forEach((modeObj) => {
      const { mode, name, callback } = modeObj;
      const btn = document.createElement('div');
      btn.className = 'transform-mode-menu-item';
      btn.setAttribute('mode', mode);
      btn.textContent = name;
      btn.addEventListener(
        'click',
        () => {
          // 重置
          this._resetTransfromControls();
          this.transformControls.setMode(mode);
          // 高亮
          document.querySelectorAll('.transform-mode-menu-item').forEach((item) => {
            item.classList.toggle('active', item.textContent === name);
          });
          // 调用
          typeof callback === 'function' && callback();
        },
        {
          signal: this.transformModeMenuAbortController.signal,
        }
      );
      menu.appendChild(btn);
    });

    // 添加快速旋转
    enableFastRotate && this.enableFastRotate();

    // 初始状态修正
    let { initialMode } = menuOption;
    initialMode = initialMode || filteredModes.length > 0 ? filteredModes[0].mode : 'translate';
    this.transformControls.mode = initialMode;
    this.transformModeMenuVisibleMode = visibleModes;
    this.transformControls.enabled = true;
    menu.querySelector('.transform-mode-menu-item')?.classList.add('active');
    // 修正初始状态的btn的click
    // visibleModes.find((item) => item.mode === initialMode)?.callback?.();
    // 找到对应attribute中mode对应为initialMode的元素，并触发其click事件
    const initialModeBtn = menu.querySelector(`[mode="${initialMode}"]`) as HTMLDivElement;
    initialModeBtn?.click();
    // 插入页面
    const { boxId } = this.option;
    const box = document.getElementById(boxId);
    box.appendChild(menu);
  }

  private _removeTransformModeMenu(): void {
    const menu = document.getElementById(TRANSFORM_MODE_MENU_ID);
    if (!menu) return;
    this.transformModeMenuAbortController.abort();
    this.transformModeMenuAbortController = null;
    this.transformModeMenuVisibleMode = [];
    this._resetTransfromControls();
    menu.remove();
  }

  /** @description 关闭轨道控制 */
  detachTransfromControls(): void {
    this._removeTransformModeMenu();
    this.transformControls.detach();
    this.transformControls.enabled = false;
    // 若启用了快速旋转，则关闭
    this.fastRotateAbortController && this.fastRotateAbortController.abort();
  }

  /**
   * @description 快速旋转，每次旋转45度-> 8个方向
   * - 请进行成对调用: enableFastRotate + disableFastRotate
   */
  enableFastRotate(object?: THREE.Object3D): void {
    if (this.fastRotateAbortController) this.disableFastRotate();
    this.fastRotateAbortController = new AbortController();
    document.addEventListener(
      'keydown',
      (event: KeyboardEvent) => {
        if (event.key === 'r' || event.key === 'R') {
          this.currentRotationStep = (this.currentRotationStep + 1) % 8;
          const ROTATION_STEP = Math.PI / 4; // 45度
          const targetAngle = -this.currentRotationStep * ROTATION_STEP;
          object = object || this.transformControls.object;
          if (!object) return;

          // 创建一个新的欧拉角，设置为目标角度（相对于世界坐标系）
          const euler = new THREE.Euler(0, targetAngle, 0, 'XYZ');

          // 应用旋转
          object.setRotationFromEuler(euler);
        }
      },
      {
        signal: this.fastRotateAbortController.signal,
      }
    );
  }

  disableFastRotate(): void {
    this.fastRotateAbortController && this.fastRotateAbortController.abort();
    this.fastRotateAbortController = null;
  }

  /**
   * @description 点击高亮拾取objects
   *  - 请进行成对调用: enableClickPicker + disableClickPicker
   */
  enableClickPicker(objects: THREE.Object3D[]): void {
    if (this.clickPickerAbortController) this.disableClickPicker();
    this.clickPickerAbortController = new AbortController();
    this._resetTransfromControls();

    const { renderer, camera } = this.option;
    const box = renderer.domElement;
    const raycaster = new THREE.Raycaster();

    box.addEventListener(
      'click',
      (event) => {
        event.preventDefault();
        const target = event.target as HTMLElement;
        const mouse = new THREE.Vector2(
          (event.offsetX / target.clientWidth) * 2 - 1,

          -(event.offsetY / target.clientHeight) * 2 + 1
        );
        raycaster.setFromCamera(mouse, camera);
        const intersects = raycaster.intersectObjects(objects);

        let selectObject = null;
        if (intersects.length > 0) {
          const { parent } = intersects[0].object;
          if (parent && parent.type === 'Group') {
            selectObject = parent;
          } else {
            selectObject = intersects[0].object;
          }
        }

        if (selectObject) {
          this.transformControls.attach(selectObject);
        } else {
          this.transformControls.detach();
        }
      },
      {
        signal: this.clickPickerAbortController.signal,
      }
    );
  }

  /**
   *  TEST
   *  解除box的click监听
   *  调用detach方法
   *  释放abortcontroller
   */
  disableClickPicker(): void {
    this.clickPickerAbortController && this.clickPickerAbortController.abort();
    this.clickPickerAbortController = null;
    this.transformControls.detach();
  }

  update(): void {
    this.orbitControls && this.orbitControls.update();
    // this.transformControls && this.transformControls.update();
  }

  /** 重置三轴显示和旋转缩放步长 */
  _resetTransfromControls(): void {
    this.transformControls.showX = true;
    this.transformControls.showY = true;
    this.transformControls.showZ = true;
    this.transformControls.rotationSnap = null;
    this.transformControls.scaleSnap = null;
  }

  destroy(): void {
    this.transformModeMenuAbortController && this.transformModeMenuAbortController.abort();
    this.fastRotateAbortController && this.fastRotateAbortController.abort();
    this.transformModeMenuAbortController = null;
    this.fastRotateAbortController = null;
    this.orbitControls && this.orbitControls.dispose();
    this.transformControls && this.transformControls.dispose();
  }
}
